<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>队列动画</title>
    <style>
        #app {
            position: absolute;
            top: 0;
            left: 0;
            width: 200px;
            height: 200px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <div id="app"></div>
    <script>
        let Queue = (function () {
            let symbol = Symbol()
            return class {
                constructor() {
                    this[symbol] = []
            }

                //入队
                enqueue(item) {
                    this[symbol].push(item)
                }

                //出队 shift() 方法用于把数组的第一个元素从其中删除，并返回第一个元素的值
                dequeue() {
                    return this[symbol].shift()
                }

                clear() {
                    this[symbol] = []
                }

                size() {
                    return this[symbol].length
                }

                print() {
                    this[symbol].forEach(value => {
                        console.log(value)
                    });
                }
            }
        })()

        let AnitmateQueue = (function (selector) {

            let dom = Symbol()
            let anitmateQueueMap = new Map()


            class _Queue extends Queue {
                constructor(props) {
                    super(props)
                    this.ifRun = false
                }

                //遍历整个动画队列，挨着执行
                run() {
                    if (this.ifRun) return
                    this.ifRun = true;
                    (function r() {
                        if (this.size()) {
                            new Promise(this.dequeue()).then(r.bind(this))
                        } else {
                            this.ifRun = false
                        }
                    }).call(this)
                }
            }

            class Init {
                constructor(selector) {
                    this[dom] = document.querySelector(selector)
                }

                //动画操作
                animate(options, time = 300) {
                    if (!anitmateQueueMap.has(this[dom])) {
                        anitmateQueueMap.set(this[dom], new _Queue())
                    }

                    let queue = anitmateQueueMap.get(this[dom])
                    
                    queue.enqueue((res) => {

                        this[dom].style.transition = time / 1000 + 's'
                        this[dom].offsetTop;

                        for (let [key, item] of Object.entries(options)) {
                            this[dom].style[key] = item + 'px'
                        }

                        setTimeout(res, time)
                    })

                    queue.run()
                    return this

                }
            }

            return function (selector) {
                return new Init(selector)
            }

        })()


        AnitmateQueue('#app')
            .animate({
                width: 300
            }, 2000)
            .animate({
                height: 300
            }, 1000)
            .animate({
                top: 200
            }, 2000)
    </script>

</body>

</html>